#include "model/vertex.h"
#include "model/halfedge.h"

#include <math.h>
#include <QDebug>

Vertex::Vertex(coord x, coord y, coord z, coord w, unsigned int index): Point(x, y, z), w(w), index(index), edge(nullptr) {}

Vertex::Vertex(const Vertex &vertex): Vertex(vertex.x, vertex.y, vertex.z, vertex.w, vertex.index) {}

Vertex::Vertex(const Point &point): Vertex(point.x, point.y, point.z) {}

Vertex::~Vertex() {}

void Vertex::apply(const MatrixTransformation &m) {
    Vertex v(*this);

    x = (m[0][0] * v.x) + (m[0][1] * v.y) + (m[0][2] * v.z) + (m[0][3] * v.w);
    y = (m[1][0] * v.x) + (m[1][1] * v.y) + (m[1][2] * v.z) + (m[1][3] * v.w);
    z = (m[2][0] * v.x) + (m[2][1] * v.y) + (m[2][2] * v.z) + (m[2][3] * v.w);
    w = (m[3][0] * v.x) + (m[3][1] * v.y) + (m[3][2] * v.z) + (m[3][3] * v.w);
}

void Vertex::updateValues(const Vertex &values) {
    x = values.x;
    y = values.y;
    z = values.z;
    w = values.w;
}

const std::list<const Face *> Vertex::getFaces() const {
    HalfEdge *e = edge;
    HalfEdge *half;

    std::list<const Face *> faces;

    do {
        faces.push_back(e->face);
        half = e->complement;

        if ( !half )
            break;

        e = half->next;
    } while( edge != e );

    if ( edge != e || faces.size() == 1 ) {
        // há alguma edge que não possui a outra metade.
        // necessário percorrer a lista no sentido anti-horário

        e = e->previous;
        do {
            half = e->complement;

            if ( !half )
                break;

            faces.push_back(e->face);
            e = half->previous;
        } while ( edge != e );
    }

    return faces;
}

const std::list<const Vertex *> Vertex::getNeighbors() const {
    HalfEdge *e = edge;
    HalfEdge *half;

    std::list<const Vertex *> neighbor;

    do {
        neighbor.push_back(e->end);
        half = e->complement;

        if ( !half )
            break;

        e = half->next;
    } while( edge != e );

    if ( edge != e || neighbor.size() == 1 ) {
        // há alguma edge que não possui a outra metade.
        // necessário percorrer a lista no sentido anti-horário

        e = e->previous;
        do {
            half = e->complement;

            if ( !half )
                break;

            neighbor.push_back(e->end);
            e = half->previous;
        } while ( edge != e );
    }

    return neighbor;
}

std::vector<HalfEdge *> Vertex::join(const std::vector<Vertex*> &points) {
    std::size_t size = points.size();
    std::vector<HalfEdge*> edges(size, nullptr);

    HalfEdge *edge;
    Vertex *begin, *end;

    // cria as arestas
    begin = points[0];
    for (std::size_t i=1; i<=size; i++) {
        end = points[i%size];
        edge = new HalfEdge(*begin, *end);
        begin->edge = edge;
        edges[i-1] = edge;
        begin = end;
    }

    // cria a lista circular
    edge = edges[0];
    edge->previous = edges[size-1];
    edge->next = edges[1];
    for (std::size_t i=1; i<size; i++) {
        edge = edges[i];
        edge->previous = edges[i-1];
        edge->next = edges[(i+1)%size];
    }

    return edges;
}

